:- import "%%/lib/data.sl" #


-- Decimal-Hexadecimal Conversions --

Dec.Hex .dec .hex :- select
	(bound .hex => HexToDec .dec .hex)
	(bound .dec => DecToHex .dec .hex) ! #

Hex.Dec .hex .dec :-
	Dec.Hex .dec .hex #

Hex2 .dec .hex :-
	bound .dec,
	let .n2 (.dec  and 15), Dec.HexDigit .n2 .digit2,
	let .dec1 (.dec shr 4),
	let .n1 (.dec1 and 15), Dec.HexDigit .n1 .digit1,
	concat .digit1 .digit2 .hex ! #

Hex4 .dec .hex :-
	bound .dec,
	let .n4 (.dec  and 15), Dec.HexDigit .n4 .digit4, let .dec3 (.dec  shr 4),
	let .n3 (.dec3 and 15), Dec.HexDigit .n3 .digit3, let .dec2 (.dec3 shr 4),
	let .n2 (.dec2 and 15), Dec.HexDigit .n2 .digit2, let .dec1 (.dec2 shr 4),
	let .n1 (.dec1 and 15), Dec.HexDigit .n1 .digit1,
	concat .digit1 .digit2 .digit3 .digit4 .hex ! #


-- Helpers --

Dec.HexDigit 10 "A" :- ! #
Dec.HexDigit 11 "B" :- ! #
Dec.HexDigit 12 "C" :- ! #
Dec.HexDigit 13 "D" :- ! #
Dec.HexDigit 14 "E" :- ! #
Dec.HexDigit 15 "F" :- ! #
Dec.HexDigit .digit .char :-
	string.number .char .digit, .digit >= 0, .digit < 10 ! #

StreamHexToDec .stream .dec .ret :-
	stream.get .stream .hexDigit !
	Dec.HexDigit .decDigit .hexDigit,
	let .accum (.dec * 16 + .decDigit) !
	StreamHexToDec .stream .accum .ret #
StreamHexToDec .stream .ret .ret :-
	stream.eof .stream #

HexToDec .dec .hex :-
	stream.createBuffer HEX-DEC-STREAM,
	stream.put HEX-DEC-STREAM .hex,
	StreamHexToDec HEX-DEC-STREAM 0 .dec,
	stream.close HEX-DEC-STREAM #

DecToHex .dec .hex :-
	let .div (.dec shr 4), let .mod (.dec and 15),
	if (.div = 0) then (
		Dec.HexDigit .mod .hex
	) else (
		DecToHex .div .divHex,
		Dec.HexDigit .mod .modHex,
		concat .divHex .modHex .hex
	) #
